#include "bonds.h"
#include "CCreditCurve.h"

Bonds::Bonds(int bond_length, int freq)
{
	frequency = freq;
	no_periods = bond_length*frequency;
	time_between_coupons = (double) 1/frequency;

	for (int i = 0; i < no_periods; i++)
	{
	   cash_date.push_back(0);
	   cash_amount.push_back(0);
	   cash_amount_discounted.push_back(0);
	   cash_amount_discounted_risky.push_back(0);
	}
	principal = 0;
	firstCouponDate = 0;
	couponPercent = 0;
	fair_value = 0;
	fair_value_risky = 0;

}
void Bonds::setPrincipal(double p)
{
	principal = p;
}
void Bonds::setfirstCouponDate(int days)
{
	firstCouponDate = days;
}
void Bonds::setCouponPercent(double c)
{
	couponPercent = c;
}
void Bonds::compute()
{

	double temp1;
	double temp2;
	double temp3;
	double temp4;
	double temp_i;
	double temp_frequency;
	double bond_yield;

	YieldCurve yc;
	yc.ReadSwapFile("input.txt");
	CCreditCurve CreditCurve;
	CreditCurve.ReadCDSFile("Spreads.txt");
	
	cash_date[0] = (double) firstCouponDate/365;
	for (int i = 1; i < no_periods; i++)
	{
		cash_date[i] = cash_date[i-1] + time_between_coupons;
	}
	for (int i = 0; i < no_periods - 1; i++)
	{
		cash_amount[i] = couponPercent*principal;
	}


	cash_amount[no_periods - 1] = couponPercent*principal + principal;
	for (int i = 0; i < no_periods ; i++)
	{
		cash_amount_discounted[i] = cash_amount[i]*yc.DiscountFactor(cash_date[i]);
		fair_value = cash_amount_discounted[i] + fair_value;
		cash_amount_discounted_risky[i] = cash_amount[i]*CreditCurve.DiscountFactor(cash_date[i]);
		fair_value_risky = cash_amount_discounted_risky[i] + fair_value_risky;
		temp1 = cash_amount_discounted[i]*cash_date[i] + temp1;
		temp2 = cash_amount_discounted_risky[i]*cash_date[i] + temp2;

	}
	duration = temp1/fair_value;
	duration_risky = temp2/fair_value_risky;
	
	temp_frequency = (double) frequency;

	bond_yield = yc.SpotRate(cash_date[no_periods-1]);
//	printf("bond_yield is %5.10f\n",bond_yield );
	temp1= 1/(fair_value*pow(1+(bond_yield/temp_frequency),2));
	temp2 = 0;
	for (int i = 0; i < no_periods ; i++)
	{     temp_i = (double) i+1;
		temp3 = (temp_i)*(temp_i+1)*(couponPercent*principal);
		temp4 = pow(temp_frequency,2)*pow(1+(bond_yield/temp_frequency),temp_i);
 		temp2 = temp3/temp4;
//		printf("temp_i, temp3, temp4,  pow(temp_frequency,2), temp_frequency are  %5.10f,%5.10f,%5.10f,%5.10f,%5.10f\n", temp_i,temp3,temp4,  pow(temp_frequency,2),temp_frequency);
	}
	convexity = temp1*temp2;

	bond_yield = yc.SpotRate(cash_date[no_periods-1]) + CreditCurve.CreditSpread(cash_date[no_periods-1]);
	temp1= 1/(fair_value*pow(1+(bond_yield/temp_frequency),2));
	temp2 = 0;
	for (int i = 0; i < no_periods ; i++)
	{     temp_i = (double) i+1;
		temp3 = (temp_i)*(temp_i+1)*(couponPercent*principal);
		temp4 = pow(temp_frequency,2)*pow(1+(bond_yield/temp_frequency),temp_i);
 		temp2 = temp3/temp4;
//		printf("temp_i, temp3, temp4,  pow(temp_frequency,2), temp_frequency are  %5.10f,%5.10f,%5.10f,%5.10f,%5.10f\n", temp_i,temp3,temp4,  pow(temp_frequency,2),temp_frequency);
	}
	convexity_risky = temp1*temp2;
}

double Bonds::getFairValue(int type)
{
	if (type == 1)
	{
		return fair_value;
	}
	else
	{
		return fair_value_risky;
	}
}
double Bonds::getDuration(int type)
{
	if (type == 1)
	{
		return duration;
	}
	else
	{
		return duration_risky;
	}
}

double Bonds::getConvexity(int type)
{
	if (type == 1)
	{
		return convexity;
	}
	else
	{
		return convexity_risky;
	}
}

void Bonds::printCashFlows()
{

    ofstream cash_flow_result("bond_cash_flows.txt");
    for (int i = 0; i < no_periods; i++)
	{
           	cash_flow_result << "Date from today (expressed numerically)= " <<cash_date[i]<< "; Non-discounted cash flow = "<< cash_amount[i]
			<<"; Discounted cash flow risk-free bond = "<<cash_amount_discounted[i]<<
			"; Discounted cash flow risky bond = "<<cash_amount_discounted_risky[i]<<endl;
	}

}
